import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;

import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;

public class MonteCarloApp extends JFrame {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private JPanel total_jpanel;
	private JComboBox set_action;
	private JPanel affichage_combo;
	private JLabel affichage_combo_jl;
	private JPanel affichage_result;
	private JLabel affichage_result_jl;
	
	private JButton single_thread;
	private JButton multi_thread;
	private int set_int;
	private String set;

	public static final String SINGLETHREAD = "Single thread";
	public static final String MULTITHREAD = "Multithread";
	
	private MonteCarloMultithread MCsimulation;
	private MonteCarloApp that = this;					// workaround to allow inner classes to access "this" object
	
	public MonteCarloApp() {
		// link to model (bidir, so model is NOT independant of view)
		this.MCsimulation = new MonteCarloMultithread(this);
		MCsimulation.loadCSVfile();

		// set up view
		this.setTitle("Monte Carlo App");
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		this.buildGUI();
		this.setLocationRelativeTo(null);			// center on screen
		this.setVisible(true);	
	}

	/**
	 * To build the interface
	 */
	private void buildGUI()
	{
		String[] tab = { "Set 1", "Set 2", "Set 3","Set 4","Set 5" };
		total_jpanel = new JPanel();
		set_action = new JComboBox(tab);

		//ecoute de la jcombo
		affichage_combo=new JPanel();
		affichage_result=new JPanel();
		affichage_combo_jl=new JLabel();
		affichage_result_jl=new JLabel();
		single_thread = new JButton(SINGLETHREAD);
		single_thread.addActionListener(new SinglethreadListener());

		//ecoute du bouton
		multi_thread = new JButton(MULTITHREAD);
		multi_thread.addActionListener(new MultithreadListener());

		//ecoute du bouton

		this.setTitle("Monte Carlo");
		this.setSize(600, 400);
		total_jpanel.setSize(600, 500);

		affichage_combo.add(affichage_combo_jl);
		affichage_result.add(affichage_result_jl);
		total_jpanel.add(set_action);
		set_action.addItemListener(new ItemState());
		total_jpanel.add(affichage_combo);
		total_jpanel.add(affichage_result);
		total_jpanel.add(single_thread);
		total_jpanel.add(multi_thread);
		
		affichage_result.setPreferredSize(new Dimension(600, 250));

		set_action.setPreferredSize(new Dimension(300, 20));
		affichage_combo.setPreferredSize(new Dimension(600, 30));
		affichage_result.setPreferredSize(new Dimension(600, 250));
		total_jpanel.setBackground(Color.BLUE);
		affichage_combo.setBackground(Color.GREEN);
		affichage_result.setBackground(Color.YELLOW);
		this.getContentPane().add(total_jpanel);
	}

	/** Récupération du set choisi dans la jcombobox
	 * **/
	class ItemState implements ItemListener 
	{
		public void itemStateChanged(ItemEvent e) 
		{
			set = (String) e.getItem();

			if(set.equals("Set 1")) 
				set_int = 0;
			else if (set.equals("Set 2"))
				set_int = 1;
			else if (set.equals("Set 3"))
				set_int = 2;
			else if (set.equals("Set 4"))
				set_int = 3;
			else if (set.equals("Set 5"))
				set_int = 4;

			affichage_set(MCsimulation.getListVariables().get(set_int));
		}
	}

	/**Ecran qui permet d'afficher le set choisi
	 * **/
	public void affichage_set(Variables var)
	{
		affichage_combo_jl.setText("CallputFlag "+var.getCallputFlag()+", s="+var.getS()+", x="+var.getX()+", t="+var.getT()+", r="+var.getR()+", b="+var.getB()+", v="
				+var.getV()+", nsteps="+var.getnSteps()+", nSimulations="+var.getnSimulations());

	}

	/** Méthode qui appelle le calcul de montecarlo en single thread lorsque il y à appui sur le bouton single thread
	 * **/


	class SinglethreadListener implements ActionListener 
	{
		public void actionPerformed(ActionEvent arg0) 
		{
					
			affichage_result_jl.setText("");
			try
			{
				multi_thread.setEnabled(false);							// disable the button during calc
				Variables var = MCsimulation.getListVariables().get(set_int);

				// We create a thread to do the calculation, display the result in a new label
				JLabel resLabel = new JLabel(); 
				that.addLabel(resLabel); 
				Thread tmc = new Thread(new MonteCarloSingleThread(that, var, set, resLabel));
				tmc.start();

				multi_thread.setEnabled(true);							// reenable the button 
			}
			catch (NumberFormatException e)
			{
				JOptionPane.showMessageDialog(that, "Please enter a valid integer", "Number format error", JOptionPane.ERROR_MESSAGE);
			}

		}
	}

	/** Méthode qui appelle le calcul de montecarlo en multi thread lorsque il y à appui sur le bouton multi thread
	 * **/
	class MultithreadListener implements ActionListener 
	{
		public void actionPerformed(ActionEvent arg0) 
		{
			
			affichage_result_jl.setText("");
			try
			{
				multi_thread.setEnabled(false);							// disable the button during calc
				Variables var = MCsimulation.getListVariables().get(set_int);

				// We create a thread to do the calculation, display the result in a new label
				JLabel resLabel = new JLabel(); 
				that.addLabel(resLabel); 
				Thread tmc = new Thread(new MonteCarloMultithread(that, var, set, resLabel));
				tmc.start();

				multi_thread.setEnabled(true);							// reenable the button 
			}
			
			catch (NumberFormatException e)
			{
				JOptionPane.showMessageDialog(that, "ERROR", "...", JOptionPane.ERROR_MESSAGE);
			}
		}

	}

	/**
	 * To display the intermediate sum
	 * @param value
	 * @param label
	 */
	public void displayIntermediateValue(String type, double value, String setNb, JLabel label) {
		// TODO Auto-generated method stub
		String info = "";
		StringBuilder sb = new StringBuilder();
		String result = "Calcul en cours... ";
		sb.append(setNb).append("   ").
		append(type).append("      ").append(result).append(value);
		info = sb.toString();
		sb.setLength(0);
		
		//label.setText("Le résultat de la simulation est "+ value);
		label.setText(info);
	}

	/**
	 * To display the final result
	 * @param value
	 * @param label
	 */
	public void displayFinalValue(String type, double value, long time_exec, String setNb, JLabel label) {
		// TODO Auto-generated method stub
		String info = "";
		StringBuilder sb = new StringBuilder();
		String resultIs = "Le résultat est ";
		String timeIs = "Temps execution : ";
		sb.append(setNb).append("   ").append(type).append("      ")
		.append(resultIs).append(value).append("   ")
		.append(timeIs).append(time_exec).append(" ms");
		info = sb.toString();
		sb.setLength(0);
		
		//label.setText("Le résultat de la simulation est "+ value);
		label.setText(info);
	}

	/**
	 * To add a new JLabel to display the result
	 * @param label
	 */
	public void addLabel(JLabel label) {
		//label.setAlignmentX(JLabel.CENTER_ALIGNMENT);
		affichage_result.add(label);
	}

	/**
	 * Run the application!
	 * @param args
	 */
	public static void main(String[] args) 
	{
		new MonteCarloApp();
	}

}